package uk.ac.sanger.dasregistry.timer;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.Date;
import java.util.List;
import java.util.Timer;

import javax.sql.DataSource;
import java.util.logging.Logger;
import org.biojava.dasobert.das.DasSpec;
import org.biojava.dasobert.dasregistry.DasSource;
import org.biojava.dasobert.dasregistry.DasValidationResult;
import org.biojava.services.das.dao.DasSourceManager;
import org.biojava.services.das.registry.DasRegistrySql;

import dasregistry.validation.Validator;

public class AutoValidation{
	
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	public static Logger logger =  Logger.getLogger("uk.ac.sanger.dasregistry.timer.AutoValidation");

	int contactParentFrequency;
	Timer timer;
	DasSourceManager dasSourceManager;
	DasRegistrySql registryBean;
	
	public DasRegistrySql getRegistry() {
		return registryBean;
	}


	public void setRegistry(DasRegistrySql registry) {
		this.registryBean = registry;
	}


	public DasSourceManager getDasSourceManager() {
		return dasSourceManager;
	}


	public void setDasSourceManager(DasSourceManager dasSourceManager) {
		this.dasSourceManager = dasSourceManager;
	}






	boolean showValidationLog = true;
	public static final int ONEHOUR = 1000 * 60 * 60 ;
	//public static final int ONEHOUR = 1000 * 60 ;
	
	/**
	 *  @params validationFrequency in milli-seconds
	 */
	public AutoValidation() {
		super();
	}

	/**
	 * run validation on everything
	 * @param ignoreAdminChecks TODO
	 * @return success or not
	 */
	public boolean runAutoValidation(boolean ignoreAdminChecks){

		System.out.println("AutoValidation called");
		DataSource dataSource = registryBean.getDataSource();
		
		int numberOfSourcesFailed=0;
		
	

		Connection conn = null ;
		boolean doValidate = false;
		try {
			conn = dataSource.getConnection();

			doValidate = dasSourceManager.doAdminChecks(conn, 
					"lastValidation" ,
					"validationStarted" ,
					"validating");
			
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if ( conn != null ) {
				try {
					conn.close();
				} catch (SQLException e) {
					e.printStackTrace();
				}
			}
		}

		if(ignoreAdminChecks){
			doValidate=true;
		}
		//toggle out for debug as want to run anyway
		if ( ! doValidate ) {
			System.out.print(" not running validation due to dao admin checks... ");
			return false;
		}
System.out.println("runnning validation ---------------------------------------------------------------------------");
		logger.info("running auto validation ...");

		
		

		// retrieve all DasSources from registry and try to validate them...
		try {
			List<DasSource> dss = registryBean.listServices();

			for ( int i =0 ; i< dss.size();i++){
				DasSource ds = dss.get(i);
				System.out.println(ds.getUrl());
				//if(!ds.getUrl().contains("batman"))continue;
				if ( showValidationLog)
					System.out.print("validating " + (i+1)+"/"+ dss.size() + " "+ ds.getUrl() +  " ");

				 Date now = new Date();
				
				 Date lease = ds.getLeaseDate();
				 long tdiff = now.getTime() - lease.getTime();
				 
				 if ( showValidationLog)
					 System.out.print(tdiff + " " + ONEHOUR + " " + now + " " + lease);
//				 if ( tdiff  < ONEHOUR){
//					 if ( showValidationLog)					 
//						 System.out.println("was checked already recently");
//					 // it was up less than one hour ago, so assume it is still fine
//					
//					 continue;
//				 }
				
				
				boolean validateVerbose = false;
				//can turn off relaxng validation approval needed for automated validation
				//but we have turned on approval needed by default so that if validating via a web page a source owner has to update their source.
				Validator validator=new Validator();

				Connection connForTypes=null;
				int auto_id=0;
				try {
					connForTypes = dataSource.getConnection() ;
					auto_id = dasSourceManager.getAutoIdForURL(ds.getUrl());
				} catch (Exception e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}finally{
					if (conn != null) {
						try {
							connForTypes.close();
						} catch (SQLException es) {
							es.printStackTrace();
						}
					}
				}
				DasValidationResult result=validator.validate(DasSpec.convertToRegistrySpecification(ds.getSpecification()), ds.getUrl(), ds.getCapabilities(), ds.getCoordinateSystem(), false, true, registryBean, String.valueOf(auto_id));
					
			}//end of validate sources loop

			} catch ( Exception e){
			e.printStackTrace();
			logger.info("could not auto-validate das sources:" + e.getMessage());
			return false;
		}

		System.out.println("number of sources that failed after autovalidation="+numberOfSourcesFailed);
	
		//sendNotificationMails(registryBean);

		releaseValidationLock(registryBean);
		
		registryBean = null;
		return true;
	}



	private void releaseValidationLock(DasRegistrySql registry) {
		System.out.println("releasing validation lock");
		DataSource dataSource = registry.getDataSource();

		Connection conn = null ;
		//boolean doValidate = false;
		try {
			conn = dataSource.getConnection();
			dasSourceManager.releaseAdminLock(conn,"validating","lastValidation");
			//as we now update the valid_capabilities tables we want
			//to tell the sources.xml returned by the registry it will need updating etc
			dasSourceManager.pingLastModified(conn);

		} catch (Exception e) { 
			e.printStackTrace();
		} finally {
			if ( conn != null) {
				try { 
					conn.close();
				} catch (SQLException e) {
					e.printStackTrace();
				}
			}
		}	
	}




	

	/** send notification mails to admins of servers that have been down for > 2 days ...
	 * @param registry the registry worker
	 */
	public void sendNotificationMails(DasRegistrySql registry) {
		//disable email notifications here if testing
		registry.sendAdminNotificationMails();
		registry.sendLastWeekWarningEmails();
		//also tell the sources cmd that the database has changed and so it needs to be regenerated
		
		
		//also need to check if source has been not valid for 1 or 2months and if so send final email
		//if not valid by 2 weeks after that final email delete the source and move to archive table
		
	}


}
